package visuals;

import options.Options;
import song.Song;
import song.TimeSignature;

import javax.swing.*;
import java.io.File;
import java.util.ArrayList;

/**
 * Created by IntelliJ IDEA.
 * User: Aleksey
 * Date: 09.01.2008
 * Time: 11:23:55
 */
public class ActionController {
    private static Boolean downbeatSelected = false;
    private static Boolean noteAllocationInBuffer = false;
    private static ArrayList<Integer> noteAllocation;
    private static Boolean barInBuffer = false;
    private static Integer bufferedBar;

    protected static Boolean getDownbeatSelected() {
        return downbeatSelected;
    }

    protected static void selectPreviousBar(Integer count) {
        Integer curBar = MainFrame.getCenterPanel().getCurrentBar();
        if (curBar == 0) {
            return;
        }
        if (count > curBar) {
            count = curBar;
        }
        MainFrame.getCenterPanel().setCurrentBar(curBar - count);
        MainFrame.getCenterPanel().setCurrentPart(0);
        repaintAndFocusCenterPanel();
    }

    protected static void selectNextBar(Integer count) {
        Integer curBar = MainFrame.getCenterPanel().getCurrentBar();
        Integer maxBar = MainFrame.getSong().getBarCount();
        if (curBar == maxBar - 1) {
            return;
        }
        if (count > maxBar - 1 - curBar) {
            count = maxBar - 1 - curBar;
        }
        MainFrame.getCenterPanel().setCurrentBar(curBar + count);
        MainFrame.getCenterPanel().setCurrentPart(0);
        repaintAndFocusCenterPanel();
    }

    protected static void copyCurrentBarToPrevious() {
        Integer curBar = MainFrame.getCenterPanel().getCurrentBar();
        if (curBar > 0) {
            if (JOptionPane.showConfirmDialog(null, "Really replace previous bar?", "Copying bar", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
                MainFrame.getSong().copyBarToAnother(curBar, curBar - 1);
                MainFrame.getCenterPanel().setCurrentBar(curBar - 1);
                MainFrame.getCenterPanel().setCurrentPart(0);
            }
        }
        repaintAndFocusCenterPanel();
    }

    protected static void copyCurrentBarToNext() {
        Integer curBar = MainFrame.getCenterPanel().getCurrentBar();
        Integer maxBar = MainFrame.getSong().getBarCount();
        if (curBar < maxBar - 1) {
            if (JOptionPane.showConfirmDialog(null, "Really replace next bar?", "Copying bar", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
                MainFrame.getSong().copyBarToAnother(curBar, curBar + 1);
                MainFrame.getCenterPanel().setCurrentBar(curBar + 1);
                MainFrame.getCenterPanel().setCurrentPart(0);
            }
        }
        else {
            if (JOptionPane.showConfirmDialog(null, "Add new bar to the end of track?", "New bar", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
                Integer tempo = MainFrame.getSong().getBar(0, curBar).getTempo();
                TimeSignature timeSignature = MainFrame.getSong().getBar(0, curBar).getTimeSignature();
                MainFrame.getSong().addBar(tempo, timeSignature);
                MainFrame.getSong().copyBarToAnother(curBar, curBar + 1);
                MainFrame.getCenterPanel().setCurrentBar(curBar + 1);
                MainFrame.getCenterPanel().setCurrentPart(0);
            }
        }
        repaintAndFocusCenterPanel();
    }

    protected static void deleteCurrentBar() {
        Integer curBar = MainFrame.getCenterPanel().getCurrentBar();
        Integer maxBar = MainFrame.getSong().getBarCount();
        if (maxBar < 2) {
            return;
        }

        if (JOptionPane.showConfirmDialog(null, "Really delete bar?", "Deleting bar", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION)
        {
            MainFrame.getSong().deleteBar(curBar);
            if (curBar == maxBar - 1) {
                MainFrame.getCenterPanel().setCurrentBar(curBar - 1);
                MainFrame.getCenterPanel().setCurrentPart(0);
            }
        }
        repaintAndFocusCenterPanel();
    }

    protected static void insertNewBarBeforeCurrent() {
        Integer curBar = MainFrame.getCenterPanel().getCurrentBar();
        Integer tempo = MainFrame.getSong().getBar(0, curBar).getTempo();
        TimeSignature timeSignature = MainFrame.getSong().getBar(0, curBar).getTimeSignature();
        MainFrame.getSong().insertBar(curBar, tempo, timeSignature);
        MainFrame.getCenterPanel().setCurrentPart(0);
        repaintAndFocusCenterPanel();
    }

    protected static void addNewBarToTheEnd() {
        Integer curBar = MainFrame.getSong().getBarCount() - 1;
        Integer tempo = MainFrame.getSong().getBar(0, curBar).getTempo();
        TimeSignature timeSignature = MainFrame.getSong().getBar(0, curBar).getTimeSignature();
        MainFrame.getSong().addBar(tempo, timeSignature);
        MainFrame.getCenterPanel().setCurrentBar(curBar + 1);
        MainFrame.getCenterPanel().setCurrentPart(0);
        repaintAndFocusCenterPanel();
    }

    protected static void saveTrack() {
        new File(Options.DEFAULT_PATH).mkdirs();
        MainFrame.getSong().saveToFile(Options.DEFAULT_PATH, MainFrame.getEastPanel().getSongName().getText());
        MainFrame.getCenterPanel().requestFocus();
    }

    protected static void cursorUp() {
        Integer currentDrum = MainFrame.getCenterPanel().getCurrentDrum();
        Integer currentBar = MainFrame.getCenterPanel().getCurrentBar();
        Integer currentPart = MainFrame.getCenterPanel().getCurrentPart();

        if (!downbeatSelected) {
            if (currentDrum > 0) {
                currentDrum--;
                MainFrame.getCenterPanel().setCurrentDrum(currentDrum);
                currentPart = MainFrame.getSong().getBar(currentDrum, currentBar).getNearestPart(MainFrame.getSong().getBar(currentDrum + 1, currentBar).getRelativeTimeShift(currentPart));
                MainFrame.getCenterPanel().setCurrentPart(currentPart);
            }
        }
        else {
            downbeatSelected = false;
            currentPart = MainFrame.getSong().getBar(currentDrum, currentBar).getNearestPart(MainFrame.getSong().getDownbeat(currentBar).getRelativeTimeShift(currentPart));
            MainFrame.getCenterPanel().setCurrentPart(currentPart);
        }
        repaintAndFocusCenterPanel();
    }

    protected static void cursorDown() {
        Integer currentDrum = MainFrame.getCenterPanel().getCurrentDrum();
        Integer currentBar = MainFrame.getCenterPanel().getCurrentBar();
        Integer currentPart = MainFrame.getCenterPanel().getCurrentPart();
        if (currentDrum < MainFrame.getSong().getTrackCount() - 1) {
            currentDrum++;
            MainFrame.getCenterPanel().setCurrentDrum(currentDrum);
            currentPart = MainFrame.getSong().getBar(currentDrum, currentBar).getNearestPart(MainFrame.getSong().getBar(currentDrum - 1, currentBar).getRelativeTimeShift(currentPart));
            MainFrame.getCenterPanel().setCurrentPart(currentPart);
        }
        else {
            if (!downbeatSelected) {
                downbeatSelected = true;
                currentPart = MainFrame.getSong().getDownbeat(currentBar).getNearestPart(MainFrame.getSong().getBar(currentDrum, currentBar).getRelativeTimeShift(currentPart));
                MainFrame.getCenterPanel().setCurrentPart(currentPart);
            }
        }
        repaintAndFocusCenterPanel();
    }

    protected static void cursorLeft() {
        Integer currentPart = MainFrame.getCenterPanel().getCurrentPart();
        if (currentPart > 0) {
            MainFrame.getCenterPanel().setCurrentPart(currentPart - 1);
        }
        repaintAndFocusCenterPanel();
    }
    
    protected static void cursorRight() {
        Integer currentDrum = MainFrame.getCenterPanel().getCurrentDrum();
        Integer currentBar = MainFrame.getCenterPanel().getCurrentBar();
        Integer currentPart = MainFrame.getCenterPanel().getCurrentPart();

        if (!downbeatSelected) {
            if (currentPart < MainFrame.getSong().getBar(currentDrum, currentBar).getPartCount() - 1) {
                MainFrame.getCenterPanel().setCurrentPart(currentPart + 1);
            }
        }
        else {
            if (currentPart < MainFrame.getSong().getDownbeat(currentBar).getPartCount() - 1) {
                MainFrame.getCenterPanel().setCurrentPart(currentPart + 1);
            }
        }
        repaintAndFocusCenterPanel();
    }

    protected static void addOrRemoveNote() {
        Integer currentDrum = MainFrame.getCenterPanel().getCurrentDrum();
        Integer currentBar = MainFrame.getCenterPanel().getCurrentBar();
        Integer currentPart = MainFrame.getCenterPanel().getCurrentPart();
        if (!downbeatSelected) {
            MainFrame.getSong().getBar(currentDrum, currentBar).getPart(currentPart).setNote(!MainFrame.getSong().getBar(currentDrum, currentBar).getPart(currentPart).getNote());
            if (MainFrame.getSong().getBar(currentDrum, currentBar).getPart(currentPart).getStyle() == null) {
                MainFrame.getSong().getBar(currentDrum, currentBar).getPart(currentPart).setStyle(0);
            }
        }
        else {
            MainFrame.getSong().getDownbeat(currentBar).getPart(currentPart).setNote(!MainFrame.getSong().getDownbeat(currentBar).getPart(currentPart).getNote());
        }
        repaintAndFocusCenterPanel();
    }

    protected static void dividePart() {
        Integer currentDrum = MainFrame.getCenterPanel().getCurrentDrum();
        Integer currentBar = MainFrame.getCenterPanel().getCurrentBar();
        Integer currentPart = MainFrame.getCenterPanel().getCurrentPart();
        if (!downbeatSelected) {
            MainFrame.getSong().getBar(currentDrum, currentBar).dividePart(currentPart);
        }
        else {
            MainFrame.getSong().getDownbeat(currentBar).dividePart(currentPart);
        }
        repaintAndFocusCenterPanel();
    }

    protected static void unitePart() {
        Integer currentDrum = MainFrame.getCenterPanel().getCurrentDrum();
        Integer currentBar = MainFrame.getCenterPanel().getCurrentBar();
        Integer currentPart = MainFrame.getCenterPanel().getCurrentPart();
        if (!downbeatSelected) {
            if (currentPart < MainFrame.getSong().getBar(currentDrum, currentBar).getPartCount() - 1) {
                MainFrame.getSong().getBar(currentDrum, currentBar).uniteParts(currentPart, currentPart+1);
            }
        }
        else {
            if (currentPart < MainFrame.getSong().getDownbeat(currentBar).getPartCount() - 1) {
                MainFrame.getSong().getDownbeat(currentBar).uniteParts(currentPart, currentPart+1);
            }
        }
        repaintAndFocusCenterPanel();
    }

    protected static void styleUp() {
        Integer currentDrum = MainFrame.getCenterPanel().getCurrentDrum();
        Integer currentBar = MainFrame.getCenterPanel().getCurrentBar();
        Integer currentPart = MainFrame.getCenterPanel().getCurrentPart();
        Song song = MainFrame.getSong();
        if (!downbeatSelected) {
            Integer curStyle = song.getBar(currentDrum, currentBar).getPart(currentPart).getStyle();
            if (curStyle > 0) {
                song.getBar(currentDrum, currentBar).getPart(currentPart).setStyle(curStyle - 1);
                for (int i = 0; i < song.getBar(currentDrum, currentBar).getPartCount(); i++) {
                    if (!song.getBar(currentDrum, currentBar).getPart(i).getNote()) {
                        song.getBar(currentDrum, currentBar).getPart(i).setStyle(curStyle - 1);
                    }
                }
            }
        }
        repaintAndFocusCenterPanel();
    }

    protected static void styleDown() {
        Integer currentDrum = MainFrame.getCenterPanel().getCurrentDrum();
        Integer currentBar = MainFrame.getCenterPanel().getCurrentBar();
        Integer currentPart = MainFrame.getCenterPanel().getCurrentPart();
        Song song = MainFrame.getSong();
        if (!downbeatSelected) {
            Integer maxStyles = song.getTrack(currentDrum).getDrum().getPosition(song.getTrack(currentDrum).getPosition()).getStyleCount();
            Integer curStyle = song.getBar(currentDrum, currentBar).getPart(currentPart).getStyle();
            if (curStyle < maxStyles - 1) {
                song.getBar(currentDrum, currentBar).getPart(currentPart).setStyle(curStyle + 1);
                for (int i = 0; i < song.getBar(currentDrum, currentBar).getPartCount(); i++) {
                    if (!song.getBar(currentDrum, currentBar).getPart(i).getNote()) {
                        song.getBar(currentDrum, currentBar).getPart(i).setStyle(curStyle + 1);
                    }
                }
            }
        }
        repaintAndFocusCenterPanel();
    }

    protected static void allLoudnessDown() {
        for (int i = 0; i < MainFrame.getSong().getTrackCount(); i++) {
            loudnessDown(i);
        }
    }

    protected static void allLoudnessUp() {
        for (int i = 0; i < MainFrame.getSong().getTrackCount(); i++) {
            loudnessUp(i);
        }
    }

    protected static void loudnessDown(Integer drumIndex) {
        Integer currentBar = MainFrame.getCenterPanel().getCurrentBar();
        Song song = MainFrame.getSong();
        if (!downbeatSelected) {
            Integer curLoudness = song.getBar(drumIndex, currentBar).getLoudness();
            if (curLoudness > 0) {
                song.getBar(drumIndex, currentBar).setLoudness(curLoudness - 1);
            }
        }
        repaintAndFocusCenterPanel();
    }

    protected static void loudnessUp(Integer drumIndex) {
        Integer currentBar = MainFrame.getCenterPanel().getCurrentBar();
        Song song = MainFrame.getSong();
        if (!downbeatSelected) {
            Integer curLoudness = song.getBar(drumIndex, currentBar).getLoudness();
            if (curLoudness < Options.DOWNBEAT_COUNT - 1) {
                song.getBar(drumIndex, currentBar).setLoudness(curLoudness + 1);
            }
        }
        repaintAndFocusCenterPanel();
    }

    protected static void copyNoteAllocation() {
        Integer currentDrum = MainFrame.getCenterPanel().getCurrentDrum();
        Integer currentBar = MainFrame.getCenterPanel().getCurrentBar();
        if (!downbeatSelected) {
            noteAllocation = MainFrame.getSong().getBar(currentDrum, currentBar).getNoteAllocation();
        }
        else {
            noteAllocation = MainFrame.getSong().getDownbeat(currentBar).getNoteAllocation();
        }
        noteAllocationInBuffer = true;
        MainFrame.getCenterPanel().requestFocus();
    }

    protected static void pasteNoteAllocation() {
        if (noteAllocationInBuffer) {
            Integer currentDrum = MainFrame.getCenterPanel().getCurrentDrum();
            Integer currentBar = MainFrame.getCenterPanel().getCurrentBar();
            if (!downbeatSelected) {
                MainFrame.getSong().getBar(currentDrum, currentBar).applyNoteAllocation(noteAllocation);
            }
            else {
                MainFrame.getSong().getDownbeat(currentBar).applyNoteAllocation(noteAllocation);
            }
        }
        repaintAndFocusCenterPanel();
    }

    protected static void copyBar() {
        bufferedBar = MainFrame.getCenterPanel().getCurrentBar();
        barInBuffer = true;
        MainFrame.getCenterPanel().requestFocus();
    }

    protected static void pasteBar() {
        if (barInBuffer && bufferedBar < MainFrame.getSong().getBarCount()) {
            MainFrame.getSong().copyBarToAnother(bufferedBar, MainFrame.getCenterPanel().getCurrentBar());
            MainFrame.getCenterPanel().setCurrentPart(0);
            repaintAndFocusCenterPanel();
        }
    }

    protected static void clearBar() {
        Integer currentDrum = MainFrame.getCenterPanel().getCurrentDrum();
        Integer currentBar = MainFrame.getCenterPanel().getCurrentBar();
        if (!downbeatSelected) {
            MainFrame.getSong().getBar(currentDrum, currentBar).clearNotes();
        }
        else {
            MainFrame.getSong().getDownbeat(currentBar).clearNotes();
        }
        repaintAndFocusCenterPanel();
    }

    protected static void clearFullBar() {
        Integer currentBar = MainFrame.getCenterPanel().getCurrentBar();
        if (!downbeatSelected) {
            for (int i = 0; i < MainFrame.getSong().getTrackCount(); i++) {
                MainFrame.getSong().getBar(i, currentBar).clearNotes();
            }
        }
        repaintAndFocusCenterPanel();
    }

    protected static void clearAll() {
        Integer currentBar = MainFrame.getCenterPanel().getCurrentBar();
        for (int i = 0; i < MainFrame.getSong().getTrackCount(); i++) {
            MainFrame.getSong().getBar(i, currentBar).clearNotes();
        }
        repaintAndFocusCenterPanel();
    }

    protected static void detalizeBar(Integer level) {
        Integer currentDrum = MainFrame.getCenterPanel().getCurrentDrum();
        Integer currentBar = MainFrame.getCenterPanel().getCurrentBar();
        Integer currentPart = MainFrame.getCenterPanel().getCurrentPart();
        if (!downbeatSelected) {
            Integer partShift = MainFrame.getSong().getBar(currentDrum, currentBar).getRelativeTimeShift(currentPart);
            MainFrame.getSong().getBar(currentDrum, currentBar).detalize(level);
            MainFrame.getCenterPanel().setCurrentPart(MainFrame.getSong().getBar(currentDrum, currentBar).getNearestPart(partShift));
        }
        else {
            Integer partShift = MainFrame.getSong().getDownbeat(currentBar).getRelativeTimeShift(currentPart);
            MainFrame.getSong().getDownbeat(currentBar).detalize(level);
            MainFrame.getCenterPanel().setCurrentPart(MainFrame.getSong().getDownbeat(currentBar).getNearestPart(partShift));
        }
        repaintAndFocusCenterPanel();
    }

    protected static void detalizeFullBar(Integer level) {
        if (!downbeatSelected) {
            Integer currentDrum = MainFrame.getCenterPanel().getCurrentDrum();
            Integer currentBar = MainFrame.getCenterPanel().getCurrentBar();
            Integer currentPart = MainFrame.getCenterPanel().getCurrentPart();

            Integer partShift = MainFrame.getSong().getBar(currentDrum, currentBar).getRelativeTimeShift(currentPart);
            for (int i = 0; i < MainFrame.getSong().getTrackCount(); i++) {
                MainFrame.getSong().getBar(i, currentBar).detalize(level);
            }
            MainFrame.getCenterPanel().setCurrentPart(MainFrame.getSong().getBar(currentDrum, currentBar).getNearestPart(partShift));
        }
        repaintAndFocusCenterPanel();
    }

    protected static void fillEachNote(Integer level) {
        Integer currentDrum = MainFrame.getCenterPanel().getCurrentDrum();
        Integer currentBar = MainFrame.getCenterPanel().getCurrentBar();
        if (!downbeatSelected) {
            MainFrame.getSong().getBar(currentDrum, currentBar).fillEach(level);
        }
        else {
            MainFrame.getSong().getDownbeat(currentBar).fillEach(level);
        }
        repaintAndFocusCenterPanel();
    }

    protected static void shiftNotesRight() {
        Integer currentDrum = MainFrame.getCenterPanel().getCurrentDrum();
        Integer currentBar = MainFrame.getCenterPanel().getCurrentBar();
        if (!downbeatSelected) {
            MainFrame.getSong().getBar(currentDrum, currentBar).shiftRight();
        }
        else {
            MainFrame.getSong().getDownbeat(currentBar).shiftRight();
        }
        repaintAndFocusCenterPanel();
    }

    protected static void shiftNotesLeft() {
        Integer currentDrum = MainFrame.getCenterPanel().getCurrentDrum();
        Integer currentBar = MainFrame.getCenterPanel().getCurrentBar();
        if (!downbeatSelected) {
            MainFrame.getSong().getBar(currentDrum, currentBar).shiftLeft();
        }
        else {
            MainFrame.getSong().getDownbeat(currentBar).shiftLeft();
        }
        repaintAndFocusCenterPanel();
    }

    protected static void selectAndNotePart(Integer drumIndex, Integer partIndex) {
        if (downbeatSelected) {
            downbeatSelected = false;
        }
        MainFrame.getCenterPanel().setCurrentDrum(drumIndex);
        MainFrame.getCenterPanel().setCurrentPart(partIndex);
        Integer currentDrum = MainFrame.getCenterPanel().getCurrentDrum();
        Integer currentBar = MainFrame.getCenterPanel().getCurrentBar();
        Integer currentPart = MainFrame.getCenterPanel().getCurrentPart();
        MainFrame.getSong().getBar(currentDrum, currentBar).getPart(currentPart).setNote(!MainFrame.getSong().getBar(currentDrum, currentBar).getPart(currentPart).getNote());
        if (MainFrame.getSong().getBar(currentDrum, currentBar).getPart(currentPart).getStyle() == null) {
            MainFrame.getSong().getBar(currentDrum, currentBar).getPart(currentPart).setStyle(0);
        }
        repaintAndFocusCenterPanel();
    }

    protected static void selectAndNoteDownbeatPart(Integer partIndex) {
        Integer currentBar = MainFrame.getCenterPanel().getCurrentBar();
        downbeatSelected = true;
        MainFrame.getCenterPanel().setCurrentPart(partIndex);
        MainFrame.getSong().getDownbeat(currentBar).getPart(partIndex).setNote(!MainFrame.getSong().getDownbeat(currentBar).getPart(partIndex).getNote());
        repaintAndFocusCenterPanel();
    }

    protected static void selectDrumLoudness(Integer drumIndex, Integer level) {
        Song song = MainFrame.getSong();
        Integer currentBar = MainFrame.getCenterPanel().getCurrentBar();
        song.getBar(drumIndex, currentBar).setLoudness(level);
        repaintAndFocusCenterPanel();
    }

    protected static void selectStyle(Integer level) {
        Integer currentDrum = MainFrame.getCenterPanel().getCurrentDrum();
        Integer currentBar = MainFrame.getCenterPanel().getCurrentBar();
        Integer currentPart = MainFrame.getCenterPanel().getCurrentPart();
        Song song = MainFrame.getSong();
        song.getBar(currentDrum, currentBar).getPart(currentPart).setStyle(level);
        for (int i = 0; i < song.getBar(currentDrum, currentBar).getPartCount(); i++) {
            if (!song.getBar(currentDrum, currentBar).getPart(i).getNote()) {
                song.getBar(currentDrum, currentBar).getPart(i).setStyle(level);
            }
        }
        repaintAndFocusCenterPanel();
    }

    private static void repaintAndFocusCenterPanel() {
        MainFrame.getCenterPanel().paintLayout();
        MainFrame.getCenterPanel().repaint();
        MainFrame.getCenterPanel().requestFocus();
    }
}
